#include "BallTrack.h"


BallTrack::BallTrack(){

    readElements();
    genTrack();

    // Initialise toutes les callList
    initVBO();
}

BallTrack::~BallTrack(){

    // Free les VBOs
	glDeleteBuffers(2, vboBlock);
}

void BallTrack::readElements(){
    allElements.push_back(new Element((char *)"data/bricks/1.txt"));
    allElements.push_back(new Element((char *)"data/bricks/2.txt"));
    allElements.push_back(new Element((char *)"data/bricks/3.txt"));

    nbTracks = allElements[0]->getNbTracks();
}

int BallTrack::getNbTracks(){
    return nbTracks;
}

int BallTrack::getSize(){
    return size;
}

void BallTrack::genTrack(){
    srand(time(NULL));
    size=0;
    for(int i=0; i < nbElements ; i++) {
        track.push_back(allElements[rand()%allElements.size()]);
        size+=track[i]->getSize();
    }

    tab = new int[size*nbTracks];
    int aajouter = 0;

    for(int k=0; k<nbElements; k++){
        for(int l=0; l<track[k]->getSize()*nbTracks; l++){
            tab[aajouter+l] = track[k]->getTab(l);
        }
        aajouter+=track[k]->getSize()*nbTracks;
    }

    /*std::cout << "*******" << std::endl;
    std::cout << size*nbTracks << std::endl;
    for(int k=0; k< size*nbTracks ; k++){
        std::cout << tab[k] << " " << std::endl;
    }
    exit(1);
    */

}

void BallTrack::initVBO(){
#ifdef VBO
    std::cout << "initVBO" << " " << vboBlock[0] << "  " << vboBlock[1] << std::endl;
    float blockArray[24] = {
        0.0, 0.0, 0.0,
        blockLargeur, 0.0, 0.0,
        blockLargeur, 0.0, blockLongueur,
        0.0, 0.0, blockLongueur,
        0.0, -blockHauteur, 0.0,
        blockLargeur, -blockHauteur, 0.0,
        blockLargeur, -blockHauteur, blockLongueur,
        0.0, -blockHauteur, blockLongueur
    };

    unsigned int idArray[24] = {
        0, 1, 2, 3,
        4, 5, 6, 7,
        3, 2, 6, 7,
        0, 1, 5, 4,
        1, 5, 6, 2,
        0, 4, 7, 3
    };

    glGenBuffers(2, &(vboBlock[0]));
	glBindBuffer(GL_ARRAY_BUFFER, vboBlock[0]);
    glBufferData(GL_ARRAY_BUFFER, 24*sizeof(float), blockArray, GL_STATIC_DRAW);
	glBindBuffer(GL_ARRAY_BUFFER, 0);

    // Buffer d'indices
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboBlock[1]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, 24*sizeof(unsigned int), idArray, GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

    std::cout << "fin initVBO" << vboBlock[0] << " " << vboBlock[1] << std::endl;
#endif
}

int BallTrack::getTab(int a){
    return tab[a];
}

void BallTrack::draw(){


    // Pour chaque ligne de block
    for (int j=0; j<size; ++j){

        glPushMatrix();

            glTranslatef(0., 0., -j*blockLongueur);

        // Pour chaque voie
        for (int i=0; i<nbTracks; ++i){


                glPushMatrix();
                    glTranslatef(i*blockLargeur, 0., 0.);
                    drawBlock(tab[i + j*nbTracks], i);
                glPopMatrix();

#ifdef DEBUG_TRACK
            std::cerr << tab[i + j*nbTracks] << "  ";
#endif
        }

        glPopMatrix();
#ifdef DEBUG_TRACK
            std::cerr << "" << std::endl;
#endif
    }

}

void BallTrack::drawBlock(int idBlock, int idTrack){

#ifdef VBO
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_ELEMENT_ARRAY_BUFFER);

    std::cout << "drawVBO" << std::endl;

    glBindBuffer(GL_ARRAY_BUFFER, vboBlock[0]);
    glVertexPointer(3, GL_FLOAT, 0, 0);

 // Ici on va appeller les listes en fonction de la tronche de la piste
    switch(idBlock){

        case 0: // block trou
            // draw nothing
        break;
        case 1: // block normal
            std::cout << "drawVBO1" << std::endl;
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboBlock[1]);
            glDrawElements(GL_QUADS, 24, GL_UNSIGNED_INT, 0);
        break;
        case 2: // block accelerateur
            std::cout << "drawVBO2" << std::endl;
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboBlock[1]);
            glDrawElements(GL_QUADS, 24, GL_UNSIGNED_INT, 0);
        break;
        case 3: // block ralentisseur
            std::cout << "drawVBO3" << std::endl;
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboBlock[1]);
            glDrawElements(GL_QUADS, 24, GL_UNSIGNED_INT, 0);
        break;
    }

    std::cout << "fin drawVBO" << std::endl;

    glDisableClientState(GL_ELEMENT_ARRAY_BUFFER);
    glDisableClientState(GL_VERTEX_ARRAY);
 #endif

    GLfloat black[] = { 0.0, 0.0, 0.0, 1.0 };
    GLfloat white[] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat red[] = { 255.0/255.0, 27.0/255.0, 2.0/255.0, 1.0 };
    GLfloat orange[] = { 255.0/255.0, 115.0/255.0, 1.0/255.0, 1.0 };
    GLfloat yellow[] = { 251.0/255.0, 233.0/255.0, 3.0/255.0, 1.0 };
    GLfloat green[] = { 115.0/255.0, 215.0/255.0, 22.0/255.0, 1.0 };
    GLfloat lightblue[] = { 18.0/255.0, 185.0/255.0, 204.0/255.0, 1.0 };
    GLfloat darkblue[] = { 34.0/255.0, 36.0/255.0, 91.0/255.0, 1.0 };
    GLfloat purple[] = { 75.0/255.0, 25.0/255.0, 93.0/255.0, 1.0 };
    float gray[] = {0.3,0.3,0.3,1.0};
    float lightgray[] = {0.5,0.5,0.5,1.0};

    if (idBlock != 0){

        //glEnable(GL_TEXTURE_2D);
        //glBindTexture(GL_TEXTURE_2D, 0);
        //glBindBuffer(GL_TEXTURE_2D, idTex[idTrack]);

        switch(idBlock){

            case 2: // accelerateur
                glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, lightgray);
            break;
            case 3: // ralentisseur
                glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, black);
            break;
            default:
                switch(idTrack){

                    case 0:
                        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, red);
                    break;
                    case 1:
                        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, orange);
                    break;
                    case 2:
                        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, yellow);
                    break;
                    case 3:
                        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, green);
                    break;
                    case 4:
                        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, lightblue);
                    break;
                    case 5:
                        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, darkblue);
                    break;
                    case 6:
                        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, purple);
                    break;
                    default:
                        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, white);
                    break;
                }
            break;
        }

        glBegin(GL_QUADS);

            // dessus
            glTexCoord2f(0.0, 0.0);
            glVertex3f(0.0,0.0,0.0);
            glTexCoord2f(1.0, 0.0);
            glVertex3f(blockLargeur,0.0,0.0);
            glTexCoord2f(1.0, 1.0);
            glVertex3f(blockLargeur,0.0,blockLongueur);
            glTexCoord2f(0.0, 1.0);
            glVertex3f(0.0,0.0,blockLongueur);
            // dessous
            glTexCoord2f(0.0, 0.0);
            glVertex3f(0.0,-blockHauteur,0.0);
            glTexCoord2f(1.0, 0.0);
            glVertex3f(blockLargeur,-blockHauteur,0.0);
            glTexCoord2f(1.0, 1.0);
            glVertex3f(blockLargeur,-blockHauteur,blockLongueur);
            glTexCoord2f(0.0, 1.0);
            glVertex3f(0.0,-blockHauteur,blockLongueur);
            // face
            glTexCoord2f(0.0, 0.0);
            glVertex3f(0.0,0.0,blockLongueur);
            glTexCoord2f(1.0, 0.0);
            glVertex3f(blockLargeur,0.0,blockLongueur);
            glTexCoord2f(1.0, 1.0);
            glVertex3f(blockLargeur,-blockHauteur,blockLongueur);
            glTexCoord2f(0.0, 1.0);
            glVertex3f(0.0,-blockHauteur,blockLongueur);
            // back
            glTexCoord2f(0.0, 0.0);
            glVertex3f(0.0,0.0,0.0);
            glTexCoord2f(1.0, 0.0);
            glVertex3f(blockLargeur,0.0,0.0);
            glTexCoord2f(1.0, 1.0);
            glVertex3f(blockLargeur,-blockHauteur,0.0);
            glTexCoord2f(0.0, 1.0);
            glVertex3f(0.0,-blockHauteur,0.0);
            // side left
            glTexCoord2f(0.0, 0.0);
            glVertex3f(blockLargeur,0.0,0.0);
            glTexCoord2f(1.0, 0.0);
            glVertex3f(blockLargeur,-blockHauteur,0.0);
            glTexCoord2f(1.0, 1.0);
            glVertex3f(blockLargeur,-blockHauteur,blockLongueur);
            glTexCoord2f(0.0, 1.0);
            glVertex3f(blockLargeur,0.0,blockLongueur);
            // side right
            glTexCoord2f(0.0, 0.0);
            glVertex3f(0.0,0.0,0.0);
            glTexCoord2f(1.0, 0.0);
            glVertex3f(0.0,-blockHauteur,0.0);
            glTexCoord2f(1.0, 1.0);
            glVertex3f(0.0,-blockHauteur,blockLongueur);
            glTexCoord2f(0.0, 1.0);
            glVertex3f(0.0,0.0,blockLongueur);

        glEnd();

        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, gray);

        //glBindBuffer(GL_TEXTURE_2D, 0);
        //glDisable(GL_TEXTURE_2D);
    }
}
